package when3meet.controller;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import client.ServerAccess;

import when3meet.model.ClientInfo;
import when3meet.model.User;
import when3meet.utilities.InputUtilities;
import when3meet.view.Application;
import when3meet.view.DecisionLinePanel;
import when3meet.view.KickUserButton;
import when3meet.view.MainFrame;
import when3meet.view.SignInFrame;
import xml.Message;

/**
 * Deal with GUI-based action- send XML request; Handle sign in response from
 * server
 * 
 * @author Xi
 * 
 */
public class SignInController implements ActionListener {

	SignInFrame signInFrame;
	MainFrame mainFrame;
	ClientInfo ci;
	ServerAccess access;

	public SignInController(SignInFrame sf) {
		signInFrame = sf;
	}

	@Override
	// GUI-based control
	public void actionPerformed(ActionEvent e) {

		// for admin login
		if (signInFrame.getIsAdmin().isSelected()) {
			AdminController ac = new AdminController();
			ac.actionPerformed(e);
		} else {

			// check event id field input
			boolean b1 = InputUtilities.checkTextFieldInput(signInFrame.getEventIDField());
			if (b1 == false) {

				signInFrame.getEventIDField().setBackground(Color.RED);
			} else {
				signInFrame.getEventIDField().setBackground(Color.WHITE);
			}
			// check user name field input
			boolean b2 = InputUtilities.checkTextFieldInput(signInFrame.getUserNameField());
			if (b2 == false) {

				signInFrame.getUserNameField().setBackground(Color.RED);
			} else {
				signInFrame.getUserNameField().setBackground(Color.WHITE);
			}

			if (b1 == true && b2 == true) {

				// send XML request
				sendRequest();

			}
		}
	}

	/**
	 * send XML request
	 */
	public void sendRequest() {
		ClientInfo ci = ClientInfo.getInstance();

		ci.setUserName(signInFrame.getUserNameField().getText());
		ci.setPassword(signInFrame.getPasswordField().getText());

		String xmlString = Message.requestHeader() + "<signInRequest " + "id = '"
				+ signInFrame.getEventIDField().getText() + "'>" + "<user " + "name = '" + ci.getUserName() + "' "
				+ "password = '" + ci.getPassword() + "'/>" + "</signInRequest>" + "</request>";

		Message m = new Message(xmlString);

		access = Application.getInstance().getServerAccess();
		access.sendRequest(m);

	}

	/**
	 * Deal with XML response, two part mainly, first, display choices; second,
	 * assign allowed edges corresponding to event behavior, asynchronous mode
	 * could add 1 edge per time, round-robin can add one edge iff the user is
	 * moderator, else wait for turn response
	 * 
	 * @param response
	 */
	public void process(Message response) {

		Node update = response.contents.getFirstChild();
		ClientInfo ci = ClientInfo.getInstance();

		NamedNodeMap map = update.getAttributes();

		// String userName = map.getNamedItem("name").getNodeValue();
		String id = map.getNamedItem("id").getNodeValue();
		String behavior = map.getNamedItem("behavior").getNodeValue();
		String type = map.getNamedItem("type").getNodeValue();
		String question = map.getNamedItem("question").getNodeValue();
		int numChoices = Integer.parseInt(map.getNamedItem("numChoices").getNodeValue());
		int numRounds = Integer.parseInt(map.getNamedItem("numRounds").getNodeValue());
		int position = Integer.parseInt(map.getNamedItem("position").getNodeValue());

		// get choices and users

		NodeList children = update.getChildNodes();
		ArrayList<String> choices = new ArrayList<String>();
		ArrayList<User> users = new ArrayList<User>();
		for (int i = 0; i < children.getLength(); i++) {
			Node n = children.item(i);
			NamedNodeMap tempMap = n.getAttributes();
			// store user's info into local model
			if (n.getNodeName().equalsIgnoreCase("user")) {
				String name = tempMap.getNamedItem("name").getNodeValue();
				String password = tempMap.getNamedItem("password").getNodeValue();

				User u = new User(name, password);
				users.add(u);
			} else if (n.getNodeName().equalsIgnoreCase("choice")) {
				String value = tempMap.getNamedItem("value").getNodeValue();
				int index = Integer.valueOf(tempMap.getNamedItem("index").getNodeValue());
				choices.add(index, value);
			}
		}

		// if the mode is open, choices may be null
		if (choices != null) {
			ci.setChoices(choices.toArray(new String[choices.size()]));
			DecisionLinePanel.getInstance(numRounds, choices.toArray(new String[choices.size()]));
		}

		// store user info into local model
		ci.setUsers(users.toArray(new User[users.size()]));

		ci.setEventID(id);
		ci.setBehavior(behavior);
		ci.setType(type);
		ci.setQuestion(question);
		ci.setNumChoices(numChoices);
		ci.setNumRounds(numRounds);
		ci.setPosition(position);

		// display added choices
		if (ci.getChoices() != null) {
			MainFrame.getInstance().getDecisionLineZone().setChoices(ci.getChoices());
		}

		// if the type of event is "open"
		if (ci.getType().equals("open")) {
			if (ci.getBehavior().equals("asynchronous")) {
				// if all the choices already been set by other users, enable
				// add edge button
				if (ci.getChoices().length == ci.getNumChoices()) {
					MainFrame.getInstance().getChoiceField().setEditable(false);
					MainFrame.getInstance().getAddChoiceButton().setEnabled(false);
					MainFrame.getInstance().getAddEdgeButton().setEnabled(true);
					MainFrame.getInstance().getDecisionLineZone().setCurrentAllowedEdge(1);
				} else {
					MainFrame.getInstance().getAddChoiceButton().setEnabled(true);
					MainFrame.getInstance().getAddEdgeButton().setEnabled(false);
				}
			} else if (ci.getBehavior().equals("roundRobin")) {
				// if all choices are all set, and current user is moderator,
				// enable add edge button
				if (ci.getChoices().length == ci.getNumChoices() && ci.isModerator()) {
					// MainFrame.getInstance().getChoiceField().setEditable(false);
					// MainFrame.getInstance().getAddChoiceButton().setEnabled(false);
					// MainFrame.getInstance().getAddEdgeButton().setEnabled(true);
					// MainFrame.getInstance().getDecisionLineZone().setCurrentAllowedEdge(1);
				} else {
					MainFrame.getInstance().getAddChoiceButton().setEnabled(true);
					MainFrame.getInstance().getAddEdgeButton().setEnabled(false);
				}
			}
		} else if (ci.getType().equals("closed")) {
			// for closed event, if the behavior is asynchronous, everyone could
			// start adding edge;
			if (ci.getBehavior().equals("asynchronous")) {
				MainFrame.getInstance().getChoiceField().setEditable(false);
				MainFrame.getInstance().getAddChoiceButton().setEnabled(false);
				MainFrame.getInstance().getAddEdgeButton().setEnabled(true);
				MainFrame.getInstance().getDecisionLineZone().setCurrentAllowedEdge(1);
			} else if (ci.getBehavior().equals("roundRobin")) {
				// if the behavior is round-robin, the moderator could start
				// adding edge, others should wait for turn response
				if (ci.isModerator()) {
					MainFrame.getInstance().getChoiceField().setEditable(false);
					MainFrame.getInstance().getAddChoiceButton().setEnabled(false);
					MainFrame.getInstance().getAddEdgeButton().setEnabled(true);
					MainFrame.getInstance().getDecisionLineZone().setCurrentAllowedEdge(1);
				} else {
					MainFrame.getInstance().getAddChoiceButton().setEnabled(false);
					MainFrame.getInstance().getAddEdgeButton().setEnabled(false);
				}
			}
		}

		// // 1. if the type is closed or current choice number equals to max
		// // allowed choice number: disable add choice button, enable add edge
		// // button; 2. if the mode is open and current choice number is less
		// then
		// // max allowed choice number, enable add choice button, disable add
		// edge
		// // button
		// if (type.equals("closed") || type == "closed") {
		// MainFrame.getInstance().getAddEdgeButton().setEnabled(true);
		// MainFrame.getInstance().getAddChoiceButton().setEnabled(false);
		// } else if (type.equals("open") || type == "open") {
		// if (ci.getCurrentChoiceNum() < numChoices)
		// MainFrame.getInstance().getAddChoiceButton().setEnabled(true);
		// else if (ci.getCurrentChoiceNum() == numChoices) {
		// MainFrame.getInstance().getAddChoiceButton().setEnabled(false);
		// MainFrame.getInstance().getAddEdgeButton().setEnabled(true);
		// }
		// }
		//
		// // num of maximum edges can add- asynchronous mode: equals to
		// // numRounds(but only one each time!)
		// // roundRobin is 0 before get a turn response
		// if (behavior == "asynchronous" || behavior.contains("asynchronous"))
		// {
		// SignInFrame.getInstance().setVisible(false);
		// SignInFrame.getInstance().dispose();
		// MainFrame.getInstance().getDecisionLineZone().setMax(1);
		// MainFrame.getInstance().setVisible(true);
		//
		// } else {
		// if (behavior.equals("roundRobin") || behavior == "roundRobin")
		// if (ci.isModerator() == true) {
		// MainFrame.getInstance().getAddEdgeButton().setEnabled(true);
		// MainFrame.getInstance().getDecisionLineZone().setMax(1);
		//
		// } else
		// // edge can only be added when get a turn response
		// MainFrame.getInstance().getAddEdgeButton()
		// .setEnabled(false);
		//
		SignInFrame.getInstance().setVisible(false);
		SignInFrame.getInstance().dispose();

		// display event name, current users
		MainFrame.getInstance().setEventName(ci.getQuestion());
		MainFrame.getInstance().getEventIdLabel().setText("Id: " + ci.getEventID());

		KickUserButton[] kickButtons = ci.getKickBtn();
		for (int i = 0; i < ci.getUsers().length; i++) {
			try {
				kickButtons[i].setText(ci.getUsers()[i].name);
				kickButtons[i].setVisible(true);
			} catch (java.lang.NullPointerException e) {

			}

		}
		ci.setKickBtn(kickButtons);

		MainFrame.getInstance().setVisible(true);
		//
		// }

	}
}
